/**
  * @file       vector.c
  * @author     const_zpc (any question please send mail to const_zpc@163.com)
  * @brief      该文件提供动态数组功能
  * @version    0.1
  * @date       2023-05-28
  *
  *
  * ********************************************************************************************************************
  * @details  功能详细说明：
  *           + 元素容量
  *                 + cotVector_Empty(cotVector_t *pVector)
  *                 + cotVector_Size(cotVector_t *pVector)
  *           + 元素访问
  *              + 单个元素访问
  *                 + cotVector_Front(cotVector_t *pVector)
  *                 + cotVector_Back(cotVector_t *pVector)
  *                 + cotVector_At(cotVector_t *pVector, size_t idx)
  *              + 数据流访问
  *                 + cotVector_Data(cotVector_t *pVector)
  *           + 元素赋值
  *                 + cotVector_Assign(cotVector_t *pVector, const void *pdata, size_t n)
  *           + 元素插入
  *                 + cotVector_Insert(cotVector_t *pVector, size_t idx, const void *pdata)
  *                 + cotVector_InsertN(cotVector_t *pVector, size_t idx, const void *pdata, size_t n)
  *                 + cotVector_Push(cotVector_t *pVector, const void *pdata)
  *           + 元素移除
  *              + 删除元素
  *                 + cotVector_Remove(cotVector_t *pVector, size_t idx)
  *                 + cotVector_RemoveN(cotVector_t *pVector, size_t idx, size_t n)
  *                 + cotVector_RemoveIf(cotVector_t *pVector, bool (*pfnCondition)(const void *pData))
  *              + 弹出元素
  *                 + cotVector_Pop(cotVector_t *pVector)
  *           + 内存交换（链表内存交换，减少内存拷贝）
  *                 + cotVector_Swap(cotVector_t *pVector1, cotVector_t *pVector2)
  * ********************************************************************************************************************
  * @par 源码路径:
  * @par 修改日志:
  * <table>
  * <tr><th>Date           <th>Version   <th>Author      <th>Description
  * <tr><td>2023-05-28     <td>1.0       <td>const_zpc       <td>初版
  * </table>
  * ********************************************************************************************************************
  */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "container/vector.h"
#include <string.h>


/**
  * @brief      初始化一个动态数组
  *
  * @note       动态数组最大容纳的数目 = buf大小/单个元素的大小
  * @param      pVector 动态数组句柄
  * @param      pBuf    动态数组占用的buf
  * @param      bufSize 动态数组占用的buf大小
  * @param      itemSize 动态数组中单个元素的大小
  */
void cotVector_Init(cotVector_t *pVector, uint8_t *pBuf, size_t bufSize, size_t itemSize)
{
    pVector->pBuf = pBuf;
    pVector->itemSize = itemSize;
    pVector->limit = bufSize / itemSize;
    pVector->sIdx = 0;
    pVector->eIdx = 0;
}

/**
  * @brief      为动态数组赋值
  *
  * @attention  该操作会替换原来所有的数据
  * @param      pVector 动态数组句柄
  * @param      pdata   赋值的元素数据
  * @param      n       赋值的元素数目
  * @return     0,成功; -1,失败
  */
int cotVector_Assign(cotVector_t *pVector, const void *pdata, size_t n)
{
    if (n >= pVector->limit)
    {
        return -1;
    }

    memcpy(pVector->pBuf, pdata, pVector->itemSize * n);
    pVector->sIdx = 0;
    pVector->eIdx = n;
    return 0;
}

/**
  * @brief      返回动态数组第一个元素数据指针
  *
  * @param      pVector 动态数组句柄
  * @return     动态数组第一个元素数据指针
  */
void *cotVector_Front(cotVector_t *pVector)
{
    if (pVector->sIdx == pVector->eIdx)
    {
        return NULL;
    }

    return pVector->pBuf + (pVector->itemSize * pVector->sIdx);
}

/**
  * @brief      返回动态数组最后一个元素数据指针
  *
  * @param      pVector 动态数组句柄
  * @return     最后一个元素数据指针
  */
void *cotVector_Back(cotVector_t *pVector)
{
    if (pVector->sIdx == pVector->eIdx)
    {
        return NULL;
    }

    return pVector->pBuf + (pVector->itemSize * (pVector->eIdx - 1));
}

/**
  * @brief      返回动态数组指定索引的元素数据指针
  *
  * @note       指定索引越界则会返回NULL
  * @param      pVector 动态数组句柄
  * @param      idx     指定索引
  * @return     指定索引的元素数据指针
  */
void *cotVector_At(cotVector_t *pVector, size_t idx)
{
    if (idx >= (pVector->eIdx - pVector->sIdx))
    {
        return NULL;
    }

    return pVector->pBuf + (pVector->itemSize * (idx + pVector->sIdx));
}

/**
  * @brief      返回动态数组第一个元素的字节指针
  *
  * @param      pVector 动态数组句柄
  * @return     字节指针
  */
uint8_t *cotVector_Data(cotVector_t *pVector)
{
    return pVector->pBuf + (pVector->itemSize * pVector->sIdx);
}

/**
  * @brief      动态数组中元素个数是否为空
  *
  * @param      pVector 动态数组句柄
  * @return     true   空
  * @return     false  非空
  */
bool cotVector_Empty(cotVector_t *pVector)
{
    if (pVector->sIdx == pVector->eIdx)
    {
        return true;
    }

    return false;
}

/**
  * @brief      返回动态数组中实际元素个数
  *
  * @param      pVector 动态数组句柄
  * @return     元素个数
  */
size_t cotVector_Size(cotVector_t *pVector)
{
    return (pVector->eIdx - pVector->sIdx);
}

/**
  * @brief      清空动态数组
  *
  * @param      pVector 动态数组句柄
  * @return     0,成功; -1,失败
  */
int cotVector_Clear(cotVector_t *pVector)
{
    pVector->sIdx = 0;
    pVector->eIdx = 0;
    return 0;
}

static int MoveMem(cotVector_t *pVector, size_t n)
{
    if (n + pVector->eIdx > pVector->limit)
    {
        if (pVector->sIdx == 0)
        {
            return -1;
        }

        size_t size = cotVector_Size(pVector);
        memmove(pVector->pBuf, pVector->pBuf + (pVector->itemSize * pVector->sIdx), size * pVector->itemSize);
        pVector->sIdx = 0;
        pVector->eIdx = size;
    }

    return 0;
}

/**
  * @brief      在动态数组中指定索引前插入一个元素
  *
  * @param      pVector 动态数组句柄
  * @param      idx     指定索引
  * @param      pdata   插入元素
  * @return     0,成功; -1,失败
  */
int cotVector_Insert(cotVector_t *pVector, size_t idx, const void *pdata)
{
    size_t tmpsidx;
    size_t offsetSize;

    if (MoveMem(pVector, 1) != 0)
    {
        return -1;
    }

    tmpsidx = pVector->sIdx + idx;
    offsetSize = pVector->itemSize * tmpsidx;

    memmove(pVector->pBuf + offsetSize + pVector->itemSize, pVector->pBuf + offsetSize, (pVector->eIdx - tmpsidx) * pVector->itemSize);
    memcpy(pVector->pBuf + offsetSize, pdata, pVector->itemSize);
    pVector->eIdx++;
    return 0;
}

/**
  * @brief      在动态数组中指定索引前插入 n 个元素
  *
  * @param      pVector 动态数组句柄
  * @param      idx     指定索引
  * @param      pdata   插入元素
  * @param      n       插入元素数目
  * @return     0,成功; -1,失败
  */
int cotVector_InsertN(cotVector_t *pVector, size_t idx, const void *pdata, size_t n)
{
    size_t tmpsidx;
    size_t offsetSize;

    if (MoveMem(pVector, n) != 0)
    {
        return -1;
    }

    tmpsidx = pVector->sIdx + idx;
    offsetSize = pVector->itemSize * tmpsidx;

    memmove(pVector->pBuf + offsetSize + (pVector->itemSize * n), pVector->pBuf + offsetSize, (pVector->eIdx - tmpsidx + n) * pVector->itemSize);
    memcpy(pVector->pBuf + offsetSize, pdata, pVector->itemSize * n);
    pVector->eIdx += n;
    return 0;
}

/**
  * @brief      删除动态数组中指定索引元素
  * 
  * @param      pVector 动态数组句柄
  * @param      idx     指定索引元素
  * @return     0,成功; -1,失败
  */
int cotVector_Remove(cotVector_t *pVector, size_t idx)
{
    size_t tmpsidx;
    size_t offsetSize;

    if (idx >= (pVector->eIdx - pVector->sIdx))
    {
        return -1;
    }

    tmpsidx = pVector->sIdx + idx;
    offsetSize = pVector->itemSize * tmpsidx;

    memmove(pVector->pBuf + offsetSize, pVector->pBuf + offsetSize + pVector->itemSize, (pVector->eIdx - tmpsidx) * pVector->itemSize);
    pVector->eIdx--;
    return 0;
}

/**
  * @brief      删除动态数组中指定n个元素
  * 
  * @param      pVector 动态数组句柄
  * @param      idx     指定起始索引元素
  * @param      n       删除的元素数目
  * @return     0,成功; -1,失败
  */
int cotVector_RemoveN(cotVector_t *pVector, size_t idx, size_t n)
{
    size_t tmpsidx;
    size_t offsetSize;

    if (idx >= (pVector->eIdx - pVector->sIdx) || n > cotVector_Size(pVector))
    {
        return -1;
    }

    tmpsidx = pVector->sIdx + idx;
    offsetSize = pVector->itemSize * tmpsidx;

    memmove(pVector->pBuf + offsetSize, pVector->pBuf + offsetSize + (pVector->itemSize * n), (pVector->eIdx - tmpsidx - n + 1) * pVector->itemSize);
    pVector->eIdx -= n;
    return 0;
}

/**
  * @brief      按照满足的条件删除动态数组中的元素
  * 
  * @param      pVector 动态数组句柄
  * @param      pfnCondition 条件回调函数
  * @return     0,成功; -1,失败
  */
int cotVector_RemoveIf(cotVector_t *pVector, bool (*pfnCondition)(const void *pData))
{
    size_t idx = 0;
    size_t size = cotVector_Size(pVector);
    void *pVal;

    while (idx <= size)
    {
        pVal = cotVector_At(pVector, idx);

        if (pVal == NULL)
        {
            break;
        }

        if (pfnCondition(pVal))
        {
            cotVector_Remove(pVector, idx);
        }
        else
        {
            idx++;
        }
    }

    return 0;
}

/**
  * @brief      在动态数组末尾增加一个元素
  *
  * @param      pVector 动态数组句柄
  * @param      pdata   元素数据
  * @return     0,成功; -1,失败
  */
int cotVector_Push(cotVector_t *pVector, const void *pdata)
{
    if (MoveMem(pVector, 1) == 0)
    {
        memcpy(pVector->pBuf + (pVector->itemSize * pVector->eIdx), pdata, pVector->itemSize);
        pVector->eIdx++;
        return 0;
    }

    return -1;
}

/**
  * @brief      弹出动态数组的第一个元素数据
  *
  * @param      pVector 动态数组句柄
  * @return     0,成功; -1,失败
  */
int cotVector_Pop(cotVector_t *pVector)
{
    if (pVector->sIdx >= pVector->eIdx)
    {
        return -1;
    }

    pVector->sIdx++;
    return 0;
}

/**
  * @brief      交换两个动态数组内存
  *
  * @param      pVector1  动态数组句柄1
  * @param      pVector2  动态数组句柄2
  */
void cotVector_Swap(cotVector_t *pVector1, cotVector_t *pVector2)
{
    cotVector_t pTmpVector = *pVector2;

    *pVector2 = *pVector1;
    *pVector1 = pTmpVector;
}